# AggregateElementCollectionAppender.java

    package org.codefilarete.stalactite.engine.configurer.resolver.elementcollection;

    import java.util.Collection;
    import java.util.Collections;
    import java.util.function.Supplier;

    import org.codefilarete.stalactite.engine.configurer.elementcollection.ElementRecord;
    import org.codefilarete.stalactite.engine.configurer.model.ResolvedElementCollectionRelation;
    import org.codefilarete.stalactite.engine.configurer.resolver.AggregateResolver.AssemblyPoint;
    import org.codefilarete.stalactite.engine.runtime.ConfiguredRelationalPersister;
    import org.codefilarete.stalactite.engine.runtime.load.EntityInflater.EntityMappingAdapter;
    import org.codefilarete.stalactite.sql.ConnectionConfiguration;
    import org.codefilarete.stalactite.sql.Dialect;
    import org.codefilarete.stalactite.sql.ddl.structure.Table;
    import org.codefilarete.stalactite.sql.result.BeanRelationFixer;
    import org.codefilarete.tool.Reflections;

    import static org.codefilarete.stalactite.engine.runtime.load.EntityJoinTree.JoinType.OUTER;
    import static org.codefilarete.tool.bean.Objects.preventNull;

    public class AggregateElementCollectionAppender {

    	private final ElementCollectionResolver elementCollectionResolver;

    	public AggregateElementCollectionAppender(Dialect dialect, ConnectionConfiguration connectionConfiguration) {
    		this.elementCollectionResolver = new ElementCollectionResolver(dialect, connectionConfiguration);
    	}

    	public <SRC, SRCID, TRGT, TRGTID, S extends Collection<TRGT>, SRCTABLE extends Table<SRCTABLE>, COLLECTIONTABLE extends Table<COLLECTIONTABLE>>
    	void append(ConfiguredRelationalPersister<SRC, SRCID> rootPersister,
    	                     ResolvedElementCollectionRelation<SRC, TRGT, S, SRCID, SRCTABLE, COLLECTIONTABLE, ElementRecord<TRGT, SRCID>> resolvedRelation,
    	                     AssemblyPoint<SRC, SRCID, TRGT, SRCTABLE> assemblyPawn) {

    		ElementCollectionResolver.ElementRecordPersister<TRGT, SRCID, COLLECTIONTABLE, ElementRecord<TRGT, SRCID>> collectionPersister = elementCollectionResolver.resolve(resolvedRelation, assemblyPawn.getRelationOwnerPersister());

    		// select management
    		Supplier<S> collectionFactory = preventNull(
    				resolvedRelation.getComponentFactory(),
    				Reflections.giveCollectionFactory(resolvedRelation.getCollectionType()));

    		// a particular collection fixer that gets raw values (elements) from ElementRecord
    		// because elementRecordPersister manages ElementRecord, so it gives them as input of the relation,
    		// hence an adaption is needed to "convert" it.
    		// Note that this code is wrongly typed: the relationFixer should be of <SRC, C> to access the property, whereas it is typed with
    		// ElementRecord<TRGT, I> to fulfill the adapter argument. There's a kind of magic here that make it works (generics type erasure, and wrong
    		// ofAdapter(..) type deduction by compiler to match the relationFixer variable.
    		BeanRelationFixer<SRC, ElementRecord<TRGT, SRCID>> relationFixer = BeanRelationFixer.ofAdapter(
    				resolvedRelation.getAccessor(),
    				collectionFactory,
    				(bean, input, collection) -> collection.add(input.getElement()));	// element value is taken from ElementRecord

    		rootPersister.getEntityJoinTree().addRelationJoin(
    				assemblyPawn.getParentJoinPoint(),
    				new EntityMappingAdapter<>(collectionPersister.getMapping()),
    				resolvedRelation.getAccessor(),
    				resolvedRelation.getJoin().getLeftKey(),
    				resolvedRelation.getJoin().getRightKey(),
    				null,
    				OUTER,
    				relationFixer,
    				Collections.emptySet(),
    				null);

    	}
    }